package com.code.soulnetty.modbus.biz;

import com.code.soulnetty.modbus.biz.msg.Message;
import com.code.soulnetty.modbus.biz.resp.DefaultUploadData;
import com.code.soulnetty.modbus.biz.resp.ModbusDeviceData;
import com.code.soulnetty.modbus.biz.resp.ProtocolReadResponse;
import com.code.soulnetty.modbus.client.message.ProtocolRequestWrap;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @author jdy
 * @date 5:48 下午
 **/
@Slf4j
public class ModbusUtils {
    private ModbusUtils() {
    }

    //通道异常时间间隔
    public static final int MAX_ERR_OFF_TIME = 30000;

    /**
     * 解析查询报文内容
     *
     * @param request
     * @param nByte
     * @param start
     * @return
     */
    public static ProtocolReadResponse decodeResponse(ProtocolRequestWrap request, byte[] nByte, int start) {
        ProtocolReadResponse response = new ProtocolReadResponse();
        int startOffset = request.requestData().first().getOffset();
        int timestamp = Math.toIntExact(System.currentTimeMillis() / 1000);
        Map<String, ModbusDeviceData> dataMap = new HashMap<>(16);
        for (Message msg : request.requestData()) {
            try {
                Number number = msg.toNumber(nByte, startOffset, start);
                if (StringUtils.isNotBlank(msg.getFormula())) {
                    number = PointUtils.exec(msg.getDataType(), msg.getFormula(), number);
                }
                deviceData(request.getPeriod(), timestamp, dataMap, msg, number);
            } catch (Exception e) {
                log.error("ERR {},{},{},{}", ByteBufUtil.hexDump(nByte), startOffset, start, msg);
                throw new RuntimeException(e);
            }
        }
        response.setSuccess(Boolean.TRUE);
        response.setData(new ArrayList<>(dataMap.values()));
        return response;
    }

    private static void deviceData(int period, int timestamp, Map<String, ModbusDeviceData> dataMap, Message msg, Number number) {
        ModbusDeviceData modbusDeviceData = dataMap.computeIfAbsent(msg.getDeviceGuid(),
                d -> {
                    ModbusDeviceData deviceData = new ModbusDeviceData();
                    deviceData.setTenantId("default");
                    deviceData.setGuid(d);
                    deviceData.setPeriod(period);
                    deviceData.setNeedPointCount(msg.getPointCount());
                    deviceData.setPoints(new ArrayList<>());
                    return deviceData;
                });
        DefaultUploadData.DefaultUploadPointData data = new DefaultUploadData.DefaultUploadPointData();
        data.setPointCode(Integer.parseInt(msg.getPointCode()));
        data.setTimestamp(timestamp);
        data.setValue(number.doubleValue());
        modbusDeviceData.getPoints().add(data);
    }
}
